#include "video.h"
#include "string.h"
#include "stdio.h"
#include "libasm.h"
#include "kernel.h"
#include "scheduler.h"
#include "command.h"

#define BCD_ASCII_L(x)  ((0x0F & (x)) + '0')
#define BCD_ASCII_H(x)  (( (0xF0 & (x)) >> 4) + '0')

typedef unsigned short u16int;
typedef unsigned char  u8int;
typedef unsigned int u32int;

static void get_datetime(int vec[]);
static void print_datetime(int vec[]);

void
init_video(videoT *v, unsigned int cursor, int active)
{
	v->cursor = cursor;
	v->active = active % 2;
	clear_screen(v);
}

void
enable_video(videoT *v)
{
	if (!v->active)
	{
		restore_screen(v);
		v->active = 1;
	}
}

void
disable_video(videoT *v)
{
	if (v->active)
	{
		save_screen(v);
		v->active = 0;
	}
}


void
write_video(videoT *v, char key, char attr)
{
	char * mem;

	mem = v->active ? mem_video : v->mem;
	mem_pos(mem, v->cursor) = key;
	mem_attr(mem, v->cursor) =  attr;
}

unsigned int
get_cursor_pos(videoT *v)
{
	return v->cursor;
}

void
set_cursor_pos(videoT *v, unsigned int cursor)
{
	unset_cursor(v);
	v->cursor = cursor;
	set_cursor(v);
}


void
clear_screen(videoT *v)
{
	unsigned int i = 0;

	/* Reiniciar el cursor */
	v->cursor = 0;

	for(i = 0; i < 23; i++)
		clear_line(v, i);
}

void
clear_line(videoT *v, unsigned int i)
{
	unsigned int j;

	i = i % LINES_COUNT;
	for(j = 0; j < LINE_LENGTH; j++ )
		clear_cell(v, i, j);
}


void
clear_cell(videoT *v, unsigned int row, unsigned int column)
{
	char * aux;

	aux = v->active ? mem_video : v->mem;

	mem_xy_pos(aux, row, column) = ' ';
	mem_xy_attr(aux, row, column) = WHITE_TXT;
}

void
scroll_screen(videoT *v)
{
	char * aux;
	aux = v->active ? mem_video : v->mem;

	/* Scroleo la ventana */
	memcpy(aux, aux + LINE_LENGTH * BYTES_PER_CELL,
			LINE_LENGTH * BYTES_PER_CELL * (LAST_LINE - 1));


	clear_line(v, LAST_LINE - 1);

	set_cursor_pos(v, v->cursor - 80);

}

void
next_line(videoT *v)
{
	set_cursor_pos(v, (v->cursor / LINE_LENGTH ) * LINE_LENGTH + LINE_LENGTH);
}


void
save_screen(videoT *v)
{
	/* Salvar el estado de la memoria de video */
	if (v->active)
		memcpy(v->mem, mem_video, SCREEN_USE_SIZE);
}


void
restore_screen(videoT *v)
{
	/* Salvar el estado de la memoria de video */
	if (!v->active)
		memcpy(mem_video, v->mem, SCREEN_USE_SIZE);
}

#define CURSOR_TXT	32
void
set_cursor(videoT *v)
{
	char * aux;

	aux = v->active ? mem_video : v->mem;
	mem_attr(aux, v->cursor) = CURSOR_TXT;
}

/*
void
set_cursor(videoT *v)		// screen_pos= -1: borro cursor
							// screen_pos= -2: restauro cursor
{
	char * aux;
	aux = v->active ? mem_video : v->mem;
	u16int cursor = v->cursor;

	//if( cursor >= 0 )
	//{
		// Preparo para setear el byte alto del cursor.
		asm volatile ("outb %1, %0" : : "dN" ((u16int)0x3D4),
						"a" ((u8int)14));
		// Seteo el byte alto del cursor.
		asm volatile ("outb %1, %0" : : "dN" ((u16int)0x3D5),
						"a" ((u8int)(cursor >> 8)));
		// Preparo para setear el byte bajo del cursor.
		asm volatile ("outb %1, %0" : : "dN" ((u16int)0x3D4),
						"a" ((u8int)15));
		// Seteo el byte bajo del cursor.
		asm volatile ("outb %1, %0" : : "dN" ((u16int)0x3D5),
						"a" ((u8int)cursor));
	//}
//	else if( cursor == -1 )
//		_DelCursor();
//	else if( cursor == -2 )
//		_RestoreCursor();
}
*/

char *
get_active_mem_video(videoT *v)
{
	return v->active ? mem_video : v->mem;
}


void
unset_cursor(videoT *v)
{
	char * aux;

	aux = v->active ? mem_video : v->mem;
	mem_attr(aux, v->cursor) = WHITE_TXT;
}

int
clock(int argc, char *argv[])
{
	static int vec[DATE_LENGTH];
	unsigned int pid;

	pid = task_exists("clock", -1);
	if (pid != 0 && pid != get_task_pid(NULL))
	{
		exit_task(0);
	}
	/* Obtener la fecha del RTC */
	get_datetime(vec);

	while (1)
	{
		print_datetime(vec);
		sleep(1);
	}

	doexit(0);
	return 0;
}



static void
get_datetime(int vec[])
{
	int i, j, flag = 1;
	char aux;
	static char regs[8] = { 0x07, 0x08, 0x32, 0x09, 0x04, 0x02, 0x00, 0 };

	memset(vec, 0, sizeof(int) * DATE_LENGTH);

	/* Leer la hora del rtc */
	for (i = 0, j = 0; i < DATE_LENGTH + 1; i++, j++)
	{
		aux = readcmos(regs[i]);
		vec[j] += (aux >> 4) * 10 + (aux & 0x0F);
		if (j == 2 && flag)
		{
			flag = 0;
			vec[j] = vec[j] * 100;
			j--;
		}
	}
}

static void
print_datetime(int vec[])
{
	/* Imprimir el da */
	mem_xy_pos(mem_video, 24, 60) = ((vec[DAY] / 10)) + '0';
	mem_xy_pos(mem_video, 24, 61) = (vec[DAY] % 10) + '0';
	mem_xy_pos(mem_video, 24, 62) = '/';
	/* Imprimir el mes */
	mem_xy_pos(mem_video, 24, 63) = (vec[MONTH] / 10) + '0';
	mem_xy_pos(mem_video, 24, 64) = (vec[MONTH] % 10) + '0';
	mem_xy_pos(mem_video, 24, 65) = '/';
	/* Imprimir el ao */
	mem_xy_pos(mem_video, 24, 66) = (vec[YEAR] / 1000) + '0';
	mem_xy_pos(mem_video, 24, 67) = ((vec[YEAR] / 100) % 10) + '0';
	mem_xy_pos(mem_video, 24, 68) = ((vec[YEAR] / 10) % 10) + '0';
	mem_xy_pos(mem_video, 24, 69) = (vec[YEAR] % 10) + '0';
	mem_xy_pos(mem_video, 24, 70) = ' ';
	/* Imprimir el mes */
	mem_xy_pos(mem_video, 24, 71) = (vec[HOUR] / 10) + '0';
	mem_xy_pos(mem_video, 24, 72) = (vec[HOUR] % 10) + '0';
	mem_xy_pos(mem_video, 24, 73) = ':';
	/* Imprimir el mes */
	mem_xy_pos(mem_video, 24, 74) = (vec[MINUTE] / 10) + '0';
	mem_xy_pos(mem_video, 24, 75) = (vec[MINUTE] % 10) + '0';
	mem_xy_pos(mem_video, 24, 76) = ':';
	/* Imprimir el mes */
	mem_xy_pos(mem_video, 24, 77) = (vec[SECOND] / 10) + '0';
	mem_xy_pos(mem_video, 24, 78) = (vec[SECOND] % 10) + '0';

	vec[SECOND]++;
	if (vec[SECOND] == 60)
	{
		vec[MINUTE]++;
		vec[SECOND] = 0;
		if (vec[MINUTE] == 60)
		{
			vec[HOUR]++;
			vec[MINUTE] = 0;
			if (vec[HOUR] == 24)
			{
				/* Si hubo un cambio de da pedirle la hora
				 * al RTC */
				get_datetime(vec);
			}
		}
	}
}

